import os

import cv2
import numpy as np
from deepface import DeepFace
from PIL import Image

from utils.logger_config import logger


def match_faces(
    source_image_path, target_dir_path, model_name="VGG-Face", distance_metric="cosine"
):
    """
    匹配源图片与目标目录中的所有图片，返回匹配的图片文件名列表

    参数:
        source_image_path: 源人脸图片路径
        target_dir_path: 目标图片目录路径
        model_name: 使用的人脸识别模型
        distance_metric: 距离度量方式
        model_dir: 模型存储目录

    返回:
        匹配的图片文件名列表
    """
    # 设置DeepFace模型目录
    # os.environ["DEEPFACE_HOME"] = os.path.abspath(model_dir)

    if not os.path.exists(source_image_path):
        raise FileNotFoundError(f"源图片不存在: {source_image_path}")

    if not os.path.exists(target_dir_path):
        raise FileNotFoundError(f"目标目录不存在: {target_dir_path}")

    # 预先加载源图片，确保它是有效的
    try:
        # 尝试使用OpenCV读取源图片
        source_img = cv2.imread(source_image_path)
        if source_img is None:
            # 如果OpenCV无法读取，尝试使用PIL
            source_img = np.array(Image.open(source_image_path).convert("RGB"))
            source_img = cv2.cvtColor(source_img, cv2.COLOR_RGB2BGR)
    except Exception as e:
        raise ValueError(f"无法读取源图片: {str(e)}")

    matched_images = []

    # 获取目标目录中的所有图片
    target_images = [
        f
        for f in os.listdir(target_dir_path)
        if f.lower().endswith((".jpg", ".jpeg", ".png"))
    ]

    for target_image in target_images:
        target_path = os.path.join(target_dir_path, target_image)
        try:
            # 尝试预先加载目标图片
            target_img = cv2.imread(target_path)
            if target_img is None:
                logger.info(f"跳过无法读取的图片: {target_image}")
                continue

            # 使用DeepFace进行人脸验证，禁用强制检测以处理可能没有人脸的图片
            result = DeepFace.verify(
                img1_path=source_image_path,
                img2_path=target_path,
                model_name=model_name,
                distance_metric=distance_metric,
                enforce_detection=False,  # 不强制检测人脸
                detector_backend="opencv",  # 使用更可靠的检测器
            )

            # 如果匹配成功，添加到结果列表
            if result["verified"]:
                matched_images.append(target_image)
                logger.info(
                    f"匹配成功: {target_image}, 距离: {result['distance']}"
                )
            else:
                logger.info(
                    f"不匹配: {target_image}, 距离: {result['distance']}"
                )

        except Exception as e:
            logger.error(f"处理图片 {target_image} 时出错: {str(e)}")
            # 尝试使用更直接的方法处理问题图片
            try:
                logger.info(
                    f"尝试使用备用方法处理 {target_image}..."
                )
                # 直接加载图像而不是使用路径
                result = DeepFace.verify(
                    img1_path=source_img,  # 直接传递图像数组
                    img2_path=target_img,  # 直接传递图像数组
                    model_name=model_name,
                    distance_metric=distance_metric,
                    enforce_detection=False,
                    detector_backend="skip",  # 完全跳过检测
                )

                if result["verified"]:
                    matched_images.append(target_image)
                    logger.info(
                        f"备用方法匹配成功: {target_image}, 距离: {result['distance']}"
                    )
            except Exception as e2:
                logger.error(f"备用方法也失败: {str(e2)}")

    return matched_images


def match_multiple_faces(
    source_dir_path, target_dir_path, model_name="VGG-Face", distance_metric="cosine"
):
    """
    遍历源目录中的所有图片与目标目录中的图片进行匹配
    每张源图片都与所有目标图片进行匹配

    参数:
        source_dir_path: 源人脸图片目录路径
        target_dir_path: 目标图片目录路径
        model_name: 使用的人脸识别模型
        distance_metric: 距离度量方式

    返回:
        匹配结果字典，键为源图片名称，值为匹配成功的目标图片及其匹配率的列表
    """
    if not os.path.exists(source_dir_path):
        raise FileNotFoundError(f"源目录不存在: {source_dir_path}")

    if not os.path.exists(target_dir_path):
        raise FileNotFoundError(f"目标目录不存在: {target_dir_path}")

    # 获取源目录中的所有图片
    source_images = [
        f
        for f in os.listdir(source_dir_path)
        if f.lower().endswith((".jpg", ".jpeg", ".png"))
    ]

    # 获取目标目录中的所有图片
    all_target_images = [
        f
        for f in os.listdir(target_dir_path)
        if f.lower().endswith((".jpg", ".jpeg", ".png"))
    ]

    # 用于存储每个源图片匹配到的目标图片及其匹配率
    match_results = {}

    for source_image in source_images:
        source_path = os.path.join(source_dir_path, source_image)
        logger.info(f"\n开始处理源图片: {source_image}")

        # 对当前源图片进行匹配
        current_matches = []
        for target_image in all_target_images:
            target_path = os.path.join(target_dir_path, target_image)
            try:
                # 尝试预先加载目标图片
                target_img = cv2.imread(target_path)
                if target_img is None:
                    logger.info(
                        f"跳过无法读取的图片: {target_image}"
                    )
                    continue

                # 使用DeepFace进行人脸验证
                result = DeepFace.verify(
                    img1_path=source_path,
                    img2_path=target_path,
                    model_name=model_name,
                    distance_metric=distance_metric,
                    enforce_detection=False,
                    detector_backend="opencv",
                )

                # 如果匹配成功，添加到结果列表
                if result["verified"]:
                    # 计算匹配率 (1 - 距离) * 100%
                    match_rate = (1 - result["distance"]) * 100
                    current_matches.append((target_image, match_rate))
                    logger.info(
                        f"匹配成功: {target_image}, 距离: {result['distance']}, 匹配率: {match_rate:.2f}%"
                    )
                else:
                    logger.info(
                        f"不匹配: {target_image}, 距离: {result['distance']}"
                    )

            except Exception as e:
                logger.error(
                    f"处理图片 {target_image} 时出错: {str(e)}"
                )
                # 这里可以添加备用处理方法，类似于match_faces函数中的备用方法

        # 记录当前源图片的匹配结果
        match_results[source_image] = current_matches
        logger.info(
            f"源图片 {source_image} 匹配到 {len(current_matches)} 张图片"
        )

    return match_results
